/**
 * @author Huynh
 * 
 * Last modified:  April 21, 2012
 */

package model;

public class BoardStructure {
	/**
	 * The board configuration of the game state board[col][row] indicate whose
	 * player the marble at that cell is.
	 */
	int board[][] = { { -1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1, -1 },
			{ -1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1, -1 },
			{ -1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1, -1 },
			{ -1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1, -1 } };

	/**
	 * The actual score for each player. This can be deduced from the
	 * scoreArray, but keep it for the sake of efficiency.
	 */
	private int score[] = { 0, 0 };

	/**
	 * The winner of the game 0 means the game has not finished 1 means the
	 * first player wins 2 means the second player wins. 3 means the game is
	 * draw.
	 */
	private int winner = -1;

	/**
	 * The number of squares occupied by the pieces on the board. This can be
	 * deduced from the array coreArray, but kept for efficiency
	 */
	private int numberOfPiece = 0;

	/**
	 * Get the row if a player choose a column. If the move is invalid, return
	 * -1.
	 */
	public int getRow(int col) {
		int row = 0;
		if (col < 0 || col > 6) { // Invalid move.
			return -1;
		}
		while (row < 6 && board[col][row] == -1) {
			row++;
		}
		row--;
		return row;
	}

	/**
	 * Set a certain cell. Check if the game is finished and find out who is the
	 * winner.
	 */
	public void setCell(int column, int row, int player) {
		board[column][row] = player;
		if (player == -1) {
			// This is a dummy player. Perhaps this function is being used to
			// fill the board.
			return;
		}
		numberOfPiece++;

		// Check if the game is finished and who is the winner.
		// Check the horizontal
		int left = column;
		int right = column;
		while (left >= 0 && board[left][row] == board[column][row])
			left--;
		while (right < 7 && board[right][row] == board[column][row])
			right++;

		// Check the vertical
		int up = row;
		int down = row;
		while (up >= 0 && board[column][up] == board[column][row])
			up--;
		while (down < 6 && board[column][down] == board[column][row])
			down++;

		// Check the diagonal [left_top -> right_bottom]
		int leftTopRow = row;
		int rightBottomRow = row;
		int leftTopCol = column;
		int rightBottomCol = column;

		while (leftTopRow >= 0 && leftTopCol >= 0
				&& board[leftTopCol][leftTopRow] == board[column][row]) {
			leftTopCol--;
			leftTopRow--;
		}

		while (rightBottomCol < 7 && rightBottomRow < 6
				&& board[rightBottomCol][rightBottomRow] == board[column][row]) {
			rightBottomCol++;
			rightBottomRow++;
		}

		// Check the diagonal [left_bottom -> right_top]
		int leftBottomRow = row;
		int rightTopRow = row;
		int leftBottomCol = column;
		int rightTopCol = column;

		while (leftBottomCol >= 0 && leftBottomRow < 6
				&& board[leftBottomCol][leftBottomRow] == board[column][row]) {
			leftBottomCol--;
			leftBottomRow++;
		}
		while (rightTopCol < 7 && rightTopRow >= 0
				&& board[rightTopCol][rightTopRow] == board[column][row]) {
			rightTopCol++;
			rightTopRow--;
		}

		// If there is a line of 4 marbles or more, the game is finished.
		if (right - left >= 5 || down - up >= 5
				|| rightBottomRow - leftTopRow >= 5
				|| leftBottomRow - rightTopRow >= 5) {

			// This player is the winner.
			winner = board[column][row];
		}

		// Update the score status
		// If there is a winner, then the score is update immediately.
		if (winner != -1) {
			score[winner] = INFINITY;
			score[1 - winner] = 0;
		} else {
			if (right - left == 4) { // 3-in-a-row
				// If this line cannot be extended, then the score does not
				// increase as much as if it is.
				if (left >= 0 && right <= 6) {
					score[player] += 16;
				}

			} else if (right - left == 3) { // 2-in-a-row
				if (right <= 6 && left >= 0) {
					score[player] += 4;
				}
			}

			if (down - up == 4) { // 3-in-a-column.
				if (up >= 0) {

				} else {
					score[player] += 1;
				}
			} else if (down - up == 3) {
				if (up >= 0) {
					score[player] += 4;
				}
			}

			if (rightBottomRow - leftTopRow == 4) {
				score[player] += 16;
			} else if (rightBottomRow - leftBottomRow == 2) {
				score[player] += 4;
			}

			if (leftBottomRow - rightTopRow == 4) {
				score[player] += 16;
			} else if (leftBottomRow - rightTopCol == 3) {
				score[player] += 4;
			}
			score[player] += 1;

		}

		// Print the score of the two players.
		// Log.i("boardStructure", "The first player: " + score[0]);
		// Log.i("boardStructure", "The second player: " + score[1]);

	}

	/**
	 * Check if the game is over.
	 */
	public Boolean isOver() {
		return (winner != -1 || numberOfPiece == 42);
	}

	/**
	 * Get the winner.
	 */
	public int getWinner() {
		return winner;
	}

	public int getGoodness(int player) {
		return score[player] - score[1 - player];
	}

	// Make a copy of this.
	public BoardStructure getBoard() {
		BoardStructure newBoardStructure = new BoardStructure();

		/* Setup an empty board */
		newBoardStructure.board = new int[7][6];
		for (int i = 0; i < 7; i++) {
			for (int j = 0; j < 6; j++) {
				newBoardStructure.board[i][j] = this.board[i][j];
			}
		}

		newBoardStructure.score[0] = this.score[0];
		newBoardStructure.score[1] = this.score[1];
		newBoardStructure.numberOfPiece = this.numberOfPiece;
		newBoardStructure.winner = this.winner;

		return newBoardStructure;
	}

	/**
	 * Get number of remaining cells.
	 */
	public int getNumberOfPiece() {
		return numberOfPiece;
	}

	public int getCell(int column, int row) {
		return board[column][row];
	}

	// make a clone of this board.
	public BoardStructure makeBoard() {
		BoardStructure result = new BoardStructure();

		// Copy the board.
		for (int i = 0; i < 7; i++) {
			System.arraycopy(board[i], 0, result.board[i], 0, 6);
		}

		// copy number of Pieces
		result.numberOfPiece = numberOfPiece;
		System.arraycopy(score, 0, result.score, 0, 2);
		result.winner = winner;

		return result;
	}

	public static final int INFINITY = 1000000;

}
